﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel.Composition;
using Group3.MediaTool.Interface;
using Group3.Framework;
using System.Reflection;
using System.IO;
using System.ComponentModel.Composition.Hosting;
using Group3.MediaTool.Data.IO;

namespace Group3.MediaTool.Provider
{
    /// <summary>
    /// @Version 1.0
    /// @Author Pascal Senjic
    /// @Comment
    ///     This class provides the generated class to the application via MEF.
    ///     http://msdn.microsoft.com/de-de/library/vstudio/dd460648.aspx
    /// </summary>
    public class ObjectProvider
    {
         public static ObjectProvider Instance { get; set; }
        [ImportMany(typeof(Group3.MediaTool.Interface.IObjectRelationModel))]
         public IEnumerable<Group3.MediaTool.Interface.IObjectRelationModel> ProvidedObjects { get; set; }

        private CompositionContainer container;
        private DirectoryCatalog drcat;
        public ObjectProvider()
        {
            //Setup the Current AppDomain, where the Current ObjectProvider lies
            //string dirname = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Classes");
            string dirname = Path.Combine(StaticConfig.pathDataDefinition, "Classes");
            string cachePath = string.Format("{0}\\Cache", dirname);
            if (!System.IO.Directory.Exists(cachePath))
                System.IO.Directory.CreateDirectory(cachePath);
           
            AppDomain.CurrentDomain.SetCachePath(cachePath);
            AppDomain.CurrentDomain.SetShadowCopyFiles();// = "true";
            AppDomain.CurrentDomain.SetShadowCopyPath(dirname);
        }
        /// <summary>
        /// Loads the generated classes into a program with MEF.
        /// That means, the loaded .dll is within the same AppDomain.
        /// </summary>
        public void DoImport()
        {
            try
            {
                #region Mef init
                //string dirname = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Classes");
                string dirname = Path.Combine(StaticConfig.pathDataDefinition, "Classes");
                if (!Directory.Exists(dirname))
                    Directory.CreateDirectory(dirname);
                drcat = new DirectoryCatalog(dirname);
                //Create the CompositionContainer with the parts in the catalog
                container = new CompositionContainer(drcat);
                //Fill the imports of this object
                container.ComposeParts(this);
                #endregion
            }
            catch (ReflectionTypeLoadException tLException)
            {
                var loaderMessages = new StringBuilder();
                loaderMessages.AppendLine("While trying to load composable parts the follwing loader exceptions were found: ");
                foreach (var loaderException in tLException.LoaderExceptions)
                {
                    loaderMessages.AppendLine(loaderException.Message);
                }

                // this is one of our custom exception types.   
                throw new Exception(loaderMessages.ToString(), tLException);
            } 
        }
        /// <summary>
        /// This Method ReImports the Parts in the DirectoryCatalog.
        /// </summary>
        public void DoReImport()
        {
            try
            {
                drcat.Refresh();
                container.ComposeParts(drcat.Parts);
            }
            catch
            {

            }
        }
        /// <summary>
        /// Releases all loaded .dll
        /// </summary>
        public void DoReleaseAllExports()
        {
            try
            {
                if (container != null)
                {
                    var currentLoaded = container.GetExports<Group3.MediaTool.Interface.IObjectRelationModel>();
                    if (currentLoaded != null && currentLoaded.Count() > 0)
                    {
                        container.ReleaseExports<Group3.MediaTool.Interface.IObjectRelationModel>(currentLoaded);
                        var files = System.IO.Directory.GetFiles(this.drcat.FullPath);
                        if (files != null)
                            foreach (var f in files)
                                System.IO.File.Delete(f);
                    }
                }
            }
            catch
            {
            }
        }
        /// <summary>
        /// here, a specific loaded dll can be released and redefined.
        /// The .dll is also released from the imported classes.
        /// </summary>
        /// <param name="classname"></param>
        public void DoReleaseExport(string classname)
        {
            try
            {
                string formatedClassName = (classname.Substring(0, 2) != "E_" ? "E_" + classname : classname);
                if (container != null)
                {
                    var currentLoaded = container.GetExports<Group3.MediaTool.Interface.IObjectRelationModel>();
                    if (currentLoaded != null && currentLoaded.Count() > 0)
                    {
                        var currentExport = currentLoaded
                            .Where(x => x.Value.GetType().Name == formatedClassName)
                            .Select(x => x);
                        if (currentExport != null)
                        {
                            container.ReleaseExport(currentExport.FirstOrDefault());
                            var files = System.IO.Directory.GetFiles(this.drcat.FullPath, formatedClassName+".*");
                            if (files != null)
                                foreach (var f in files)
                                    System.IO.File.Delete(f);
                        }
                    }
                }
            }
            catch (Exception)
            {

            }
        }
        /// <summary>
        /// Dispose fully loaded libraries.
        /// </summary>
        public void DoDispose()
        {
            try
            {
                if (container != null)
                {
                    container.Dispose();
                }
            }
            catch (Exception)
            {

            }
        }

    }
}
